#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "mhscpu.h"
#include "dma_test.h"
#include "ring_buffer.h"

#define BUFSIZE		  2048

typedef struct
{
	UART_TypeDef *UART;
	uint8_t *ReceBuf;
	uint8_t *SendBuf;
}UART_DMATestStructure;

#define TEST_UART_X

static void UART_BufferFree(void);
static int32_t UART_StructureInit(void);
static void RCC_Configuration(void);
static void UART_Configuration(void);
static void DMA_Configuration_UART_To_Memory(UART_DMATestStructure *UART, DMA_TypeDef *DMA_Channel);
static void DMA_Configuration_Memory_To_UART(UART_DMATestStructure *UART, DMA_TypeDef *DMA_Channel);

/*
 *	UARTx.Send -> UARTy.Rece
 *	UARTy.Rece -> UARTx.Rece
 *	Comp(UARTx.Send, UARTx.Rece)
 */
static UART_TypeDef *UARTx	= UART1;
//static UART_TypeDef *UARTy	= UART2;

static UART_DMATestStructure UARTx_Structure;
static UART_DMATestStructure UARTy_Structure;


void UART_DMA_Test(void)
{
	uint32_t i = 0;

	RCC_Configuration();
	if (0 != UART_StructureInit())
	{
		return ;
	}
	UART_Configuration();
	DMA_Cmd(ENABLE);
	/*
	 *	Memory To UARTx Tx
	 *	UARTy Rx To Memory
	 */
	//memory -> DMA -> UART1 -> UART2 -> DMA -> memory
	DMA_Configuration_Memory_To_UART(&UARTx_Structure, DMA_Channel_0);
	DMA_Configuration_UART_To_Memory(&UARTy_Structure, DMA_Channel_1);
	
	//Clear Rx RBR(if Using FIFO, Clear FIFO)
	while(UART_GetLineStatus(UARTy_Structure.UART) & UART_IT_ID_RX_RECVD)
	{
		UARTy_Structure.UART->OFFSET_0.RBR;
	}
	for (i = 0; i < (BUFSIZE / 8); i++)
	{
		//channel_1: UART2 RX To memory
		DMA_ChannelCmd(DMA_Channel_1, ENABLE);
		//channel_0: memory To UART1 TX
		DMA_ChannelCmd(DMA_Channel_0, ENABLE);
		while (TRUE)
		{
			if((DMA_GetRawStatus(DMA_Channel_0 ,DMA_IT_BlockTransferComplete) == SET)&&
				(DMA_GetRawStatus(DMA_Channel_1 ,DMA_IT_BlockTransferComplete) == SET))
			{
				DMA_ClearITPendingBit(DMA_Channel_0, DMA_IT_BlockTransferComplete);
				DMA_ClearITPendingBit(DMA_Channel_1, DMA_IT_BlockTransferComplete);
				break;
			}
		}
	}
	DMA_ChannelCmd(DMA_Channel_0, DISABLE);
	DMA_ChannelCmd(DMA_Channel_1, DISABLE);

	memcpy(UARTy_Structure.SendBuf, UARTy_Structure.ReceBuf, BUFSIZ);

	
	/*
	 *	Memory To UARTx Tx
	 *	UARTy Rx To Memory
	 */
	//memory -> DMA -> UART2 -> UART1 -> DMA -> memory
	DMA_Configuration_Memory_To_UART(&UARTy_Structure, DMA_Channel_2);
	DMA_Configuration_UART_To_Memory(&UARTx_Structure, DMA_Channel_3);
	
	//Clear Rx RBR(if Using FIFO, Clear FIFO)
	while(UART_GetLineStatus(UARTx_Structure.UART) & UART_IT_ID_RX_RECVD)
	{
		UARTx_Structure.UART->OFFSET_0.RBR;
	}
	for (i = 0; i < (BUFSIZE / 8); i++)
	{
		//channel_3: UARTx RX To memory
		DMA_ChannelCmd(DMA_Channel_3, ENABLE);
		//channel_2: memory To UARTy TX
		DMA_ChannelCmd(DMA_Channel_2, ENABLE);
		while (TRUE)
		{
			if((DMA_GetRawStatus(DMA_Channel_2 ,DMA_IT_BlockTransferComplete) == SET)&&
				(DMA_GetRawStatus(DMA_Channel_3 ,DMA_IT_BlockTransferComplete) == SET))
			{
				DMA_ClearITPendingBit(DMA_Channel_2, DMA_IT_BlockTransferComplete);
				DMA_ClearITPendingBit(DMA_Channel_3, DMA_IT_BlockTransferComplete);
				break;
			}
		}
	}
	DMA_ChannelCmd(DMA_Channel_2, DISABLE);
	DMA_ChannelCmd(DMA_Channel_3, DISABLE);
	
	if (0 == (memcmp(UARTx_Structure.SendBuf, UARTx_Structure.ReceBuf, BUFSIZ)))
	{
		printf("DMA Test(On UART) Success\n");
	}
	else
	{
		printf("DMA Test(On UART) Failed\n");

	}
	UART_BufferFree();
}

static int32_t UART_StructureInit(void)
{
	uint32_t i;
	UARTx_Structure.UART = UARTx;
//	UARTy_Structure.UART = UARTy;
	
	UARTx_Structure.ReceBuf = (uint8_t *)calloc(BUFSIZE, sizeof(uint8_t));
	UARTx_Structure.SendBuf = (uint8_t *)calloc(BUFSIZE, sizeof(uint8_t));
	UARTy_Structure.ReceBuf = (uint8_t *)calloc(BUFSIZE, sizeof(uint8_t));
	UARTy_Structure.SendBuf = (uint8_t *)calloc(BUFSIZE, sizeof(uint8_t));
	
	if(!(UARTx_Structure.ReceBuf && UARTx_Structure.SendBuf &&
		UARTy_Structure.ReceBuf && UARTy_Structure.SendBuf))
	{
		printf("DMA Test UART_StructureInit() mallic failed!\n");
		UART_BufferFree();
		return -1;
	}

	/*
	 *	Set UARTx SendBuf 0 - 255
	 */
	for (i = 0; i < BUFSIZE; i++)
	{
		UARTx_Structure.SendBuf[i] = i % 256;
	}
	return 0;
}

static void UART_BufferFree(void)
{
	if(UARTx_Structure.ReceBuf)
		free(UARTx_Structure.ReceBuf);
	if(UARTx_Structure.SendBuf)
		free(UARTx_Structure.SendBuf);
	if(UARTy_Structure.ReceBuf)
		free(UARTy_Structure.ReceBuf);
	if(UARTy_Structure.SendBuf)
		free(UARTy_Structure.SendBuf);
}
static void RCC_Configuration(void)
{
    SYSCTRL_AHBPeriphClockCmd(SYSCTRL_AHBPeriph_DMA,ENABLE);
    SYSCTRL_AHBPeriphResetCmd(SYSCTRL_AHBPeriph_DMA, ENABLE);
    
    SYSCTRL_APBPeriphClockCmd(SYSCTRL_APBPeriph_UART1, ENABLE);
	SYSCTRL_APBPeriphResetCmd(SYSCTRL_APBPeriph_UART1, ENABLE);
}

static void UART_Configuration(void)
{
	UART_InitTypeDef UART_InitStructure;
	UART_FIFOInitTypeDef UART_FIFOInitStruct;

	UART_StructInit(&UART_InitStructure);
	UART_FIFOStructInit(&UART_FIFOInitStruct);

	UART_InitStructure.UART_BaudRate = 115200;
	UART_InitStructure.UART_WordLength = UART_WordLength_8b;
	UART_InitStructure.UART_StopBits = UART_StopBits_1;
	UART_InitStructure.UART_Parity = UART_Parity_No;


	UART_FIFOInitStruct.FIFO_Enable = DISABLE;
	UART_FIFOInitStruct.FIFO_RX_Trigger = UART_FIFO_RX_Trigger_1_4_Full;
	UART_FIFOInitStruct.FIFO_TX_Trigger = UART_FIFO_TX_Trigger_1_4_Full;
	UART_FIFOInitStruct.FIFO_TX_TriggerIntEnable = ENABLE;

	UART_FIFOInit(UARTx_Structure.UART, &UART_FIFOInitStruct);
	UART_FIFOInit(UARTy_Structure.UART, &UART_FIFOInitStruct);
	UART_Init(UARTx_Structure.UART, &UART_InitStructure);
	UART_Init(UARTy_Structure.UART, &UART_InitStructure);
}

static void DMA_Configuration_UART_To_Memory(UART_DMATestStructure *UART, DMA_TypeDef *DMA_Channel)
{
	DMA_InitTypeDef DMA_InitStruct;

	DMA_ChannelCmd(DMA_Channel, DISABLE);
	//UART2_RX to memory
	DMA_InitStruct.DMA_DIR = DMA_DIR_Peripheral_To_Memory;
	if (UART0 == UART->UART)
	{
		DMA_InitStruct.DMA_Peripheral = (uint32_t)UART0;
	} 
	else if (UART1 == UART->UART)
	{
		DMA_InitStruct.DMA_Peripheral = (uint32_t)UART1;
	} 

	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(UART->UART->OFFSET_0.RBR);
	DMA_InitStruct.DMA_PeripheralInc = DMA_Inc_Nochange;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Byte;
	DMA_InitStruct.DMA_PeripheralBurstSize = DMA_BurstSize_1;
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&UART->ReceBuf[0];
	DMA_InitStruct.DMA_MemoryInc = DMA_Inc_Increment;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Byte;
	DMA_InitStruct.DMA_MemoryBurstSize= DMA_BurstSize_1;
	DMA_InitStruct.DMA_BlockSize = 8;
	DMA_InitStruct.DMA_PeripheralHandShake = DMA_PeripheralHandShake_Hardware;

	DMA_Init(DMA_Channel,&DMA_InitStruct);
	DMA_ITConfig(DMA_Channel, DMA_IT_BlockTransferComplete, ENABLE);
}

static void DMA_Configuration_Memory_To_UART(UART_DMATestStructure *UART, DMA_TypeDef *DMA_Channel)
{
	DMA_InitTypeDef DMA_InitStruct;

	
	DMA_ChannelCmd(DMA_Channel, DISABLE);
	//UART1_RX to memory
	DMA_InitStruct.DMA_DIR = DMA_DIR_Memory_To_Peripheral;
	if (UART0 == UART->UART)
	{
		DMA_InitStruct.DMA_Peripheral = (uint32_t)UART0;
	} 
	else if (UART1 == UART->UART)
	{
		DMA_InitStruct.DMA_Peripheral = (uint32_t)UART1;
	} 

	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(UART->UART->OFFSET_0.RBR);
	DMA_InitStruct.DMA_PeripheralInc = DMA_Inc_Nochange;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_DataSize_Byte;
	DMA_InitStruct.DMA_PeripheralBurstSize = DMA_BurstSize_1;
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&UART->SendBuf[0];
	DMA_InitStruct.DMA_MemoryInc = DMA_Inc_Increment;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_DataSize_Byte;
	DMA_InitStruct.DMA_MemoryBurstSize= DMA_BurstSize_1;
	DMA_InitStruct.DMA_BlockSize = 8;
	DMA_InitStruct.DMA_PeripheralHandShake = DMA_PeripheralHandShake_Hardware;

	DMA_Init(DMA_Channel,&DMA_InitStruct);
	DMA_ITConfig(DMA_Channel, DMA_IT_BlockTransferComplete, ENABLE);
}

